/**
 * <one line to give the program's name and a brief idea of what it does.>
 * Copyright (C) Aug 2, 2011  Isaias
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package redclient;

import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import redclient.util.AES;

/**
 *
 * @author Isaias
 * @file RedmineCredentials.java
 */
public class RedmineCredentials implements Serializable {

    private static int currentInternalId = 0;

    private int internalId;

    private String instanceName;

    private String host;

    private String username;

    transient private String password;

    private String proxyhost;

    private int proxyport;

    private int refreshTime;

    private boolean active;
    
    private String dateFormat;

    public RedmineCredentials()
    {
        internalId = ++currentInternalId;
    }

    public int getInternalId() {
        return internalId;
    }

    public RedmineCredentials(String username, String password, String host) {
        this.username = username;
        this.password = password;
        this.host = host;
    }

    public boolean isSameInstance(RedmineCredentials other)
    {
        boolean equalsResult = host.equals(other.host)
                    && username.equals(other.username)
                    && password.equals(other.password);

        return equalsResult;
    }

    @Override
    public boolean equals(Object object)
    {
        boolean equalsResult = false;
        if( object instanceof RedmineCredentials )
        {
            RedmineCredentials other = (RedmineCredentials)object;
            equalsResult = instanceName.equals(other.instanceName);
        }
        return equalsResult;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 59 * hash + (this.host != null ? this.host.hashCode() : 0);
        return hash;
    }

    @Override
    public String toString() {
        return this.instanceName;
    }


    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }

    /**
     * @return the host
     */
    public String getHost() {
        return host;
    }

    /**
     * @param host the host to set
     */
    public void setHost(String host) {
        this.host = host;
    }

    /**
     * @return the proxyhost
     */
    public String getProxyhost() {
        return proxyhost;
    }

    /**
     * @param proxyhost the proxyhost to set
     */
    public void setProxyhost(String proxyhost) {
        this.proxyhost = proxyhost;
    }

    /**
     * @return the proxyport
     */
    public int getProxyport() {
        return proxyport;
    }

    /**
     * @param proxyport the proxyport to set
     */
    public void setProxyport(int proxyport) {
        this.proxyport = proxyport;
    }

    /**
     * @return the instanceName
     */
    public String getInstanceName() {
        return instanceName;
    }

    /**
     * @param instanceName the instanceName to set
     */
    public void setInstanceName(String instanceName) {
        this.instanceName = instanceName;
    }

    /**
     * @return the refreshTime
     */
    public int getRefreshTime() {
        return refreshTime;
    }

    /**
     * @param refreshTime the refreshTime to set
     */
    public void setRefreshTime(int refreshTime) {
        this.refreshTime = refreshTime;
    }

    /**
     * @return the active
     */
    public boolean isActive() {
        return active;
    }

    /**
     * @param active the active to set
     */
    public void setActive(boolean active) {
        this.active = active;
    }
    
        /**
     * @return the dateFormat
     */
    public String getDateFormat() {
        return dateFormat;
    }

    /**
     * @param dateFormat the dateFormat to set
     */
    public void setDateFormat(String dateFormat) {
        this.dateFormat = dateFormat;
    }

    /**
     * Reads credentials from HD
     * @return List<RedmineCredentials>
     * @throws IOException
     */
    public static List<RedmineCredentials> getCredentials() throws IOException
    {
        List<RedmineCredentials> credentials = null;
        File configDir = new File("conf");
        if( configDir.exists() ){
            if ( ! configDir.isDirectory() ){
                configDir.mkdir();
            }
            File redmineFile = new File(configDir, "redmine.conf");
            if ( redmineFile.exists() && redmineFile.isFile() )
            {
                FileInputStream fis = new FileInputStream(redmineFile);
                ObjectInputStream ois = new ObjectInputStream(fis);
                try
                {
                    credentials =  new ArrayList<RedmineCredentials>();
                    RedmineCredentials cred = null;
                    while( (cred = (RedmineCredentials)ois.readObject()) != null )
                    {
                        if( currentInternalId < cred.getInternalId() )
                        {
                            currentInternalId = cred.getInternalId();
                        }
                        credentials.add(cred);
                    }
                }
                catch(EOFException eofe)
                {
                    //does nothing
                }
                catch(ClassNotFoundException cnfe)
                {
                    cnfe.printStackTrace(System.out);
                }
                catch(FileNotFoundException fnfe)
                {
                    fnfe.printStackTrace(System.out);
                }
                catch(IOException ioe)
                {
                    ioe.printStackTrace(System.out);
                }
                finally
                {
                    ois.close();
                }
            }
            else{
                credentials =  new ArrayList<RedmineCredentials>();
            }
        }
        else
        {
            configDir.mkdir();
            credentials =  new ArrayList<RedmineCredentials>();
        }

        return credentials;
    }

    /**
     * Persists credentials to HD
     * @param List<RedmineCredentials>
     * @throws IOException
     */
    public static void StoreCredentials(List<RedmineCredentials> credentials)  throws IOException
    {
        try
        {
            File configDir = new File("conf");
            File redmineFile = new File(configDir, "redmine.conf");
            FileOutputStream fos = new FileOutputStream(redmineFile);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            for(RedmineCredentials cred : credentials)
            {
                oos.writeObject(cred);
            }
            oos.close();
        }
        catch(FileNotFoundException fnfe)
        {
            fnfe.printStackTrace(System.out);
        }
    }

    private void writeObject(ObjectOutputStream oos)
    {
        try{
           oos.defaultWriteObject();
           String encrypted = AES.encrypt(password);
           oos.writeObject(encrypted);
        }
        catch(Exception e)
        {
            e.printStackTrace(System.out);
        }
    }

    private void readObject(ObjectInputStream ois)
    {
        try{
            ois.defaultReadObject();
            String encrypted = (String)ois.readObject();
            password = AES.decrypt(encrypted);
        }
        catch(Exception e)
        {
            e.printStackTrace(System.out);
        }
    }
}
